<!DOCTYPE html>
<html lang="en">

<head>
	<meta charset="UTF-8">
	<meta name="viewport" content="width=device-width, initial-scale=1.0">
	<title>Document</title>
	<style>
		.test {
			color: rgb(216, 3, 3);
		}

		.cvs {
			border: none;
			box-shadow: 0 0 2px #666;
			background-color: rgba(235, 248, 240, 0.7);
		}

		.toolBox {
			display: flex;
			flex-wrap: wrap;
		}

		.cvsContainer {
			display: flex;
		}

		.btn {
			outline: none;
			background-color: #09f;
			color: #fff;
			padding: 3px;
			border-radius: 2px;
			border: none;
			box-sizing: border-box;
			cursor: pointer;
		}

		.btn:hover {
			background-color: rgb(7, 121, 214);
			transition: background-color 200ms;
		}

		.btn:active {
			background-color: rgb(115, 192, 243);
		}

		.btnTool {
			padding: 4px;
			flex-grow: 1;
			background-color: #bff1ed;
			height: auto;
		}

		.toolBox>div {
			padding: 2px 6px;
		}

		
	</style>
</head>

<body>

	<div id="root">
		<div class="cvsContainer">
			<canvas id="puppeteerScreenShortcvs" class="cvs" width="800" height="700"></canvas>
			<div class="btnTool">
                <button id="btn0" class="btn">全部隐藏</button>
                <button id="btn1" class="btn">更新</button>

				<div id="selectBtns">

				</div>
			</div>
		</div>
		<div class="toolBox">
			<button id="btn_cvs_add" class="btn">画布扩大+</button>
			<button id="btn_cvs_reduce" class="btn">画布缩小-</button>

			<div>中心坐标:<span id="cameraXY">x: y:</span></div>
			<div>鼠标坐标:<span id="mouseXY">x: y:</span></div>
			<div>画布范围:<span id="winLimit">xmin: ymin: xmax: ymax</span></div>
			<div>缩放倍率:<input id="scaleRate" value="1" type="number"></input></div>
			<div>渲染symbol:<span id="renderSymbol"></span></div>
		</div>
	</div>







	<script src="./cat.js"></script>
	<script>
		let winLimitEl = document.querySelector("#winLimit");
		let renderSymbolEl = document.querySelector("#renderSymbol");

		let btn_cvs_add = document.querySelector("#btn_cvs_add");
		let btn_cvs_reduce = document.querySelector("#btn_cvs_reduce");

		class ScottMath {
			constructor() { }

			lineLength(line) { // 返回线段长度
				return Math.sqrt((line.xe - line.xs) ** 2 + (line.ye - line.ys) ** 2)
			}
			p2p(p1, p2) { // 点到点距离 输入 {x: y:}, {x: y:}
				return Math.sqrt((p2.x - p1.x) ** 2 + (p2.y - p1.y) ** 2)
			}
			angleToPi(angle) { // 角度转pi 如 输入 180 输出 3.1415...
				return Math.PI / 180 * angle
			}


			lineLengthAdd(line, length) { // 线段长度向两端增减 返回增减后的线段 length 是单端增减长度
				if (line.xe - line.xs == 0 || line.ye - line.ys == 0) {
					if (line.xe - line.xs == 0) {
						return {
							xs: line.xs,
							ys: line.ys + (line.ye - line.ys > 0 ? -length : length),
							xe: line.xe,
							ye: line.ye + (line.ye - line.ys > 0 ? length : -length)
						}
					} else {
						return {
							xs: line.xs - (line.xe - line.xs > 0 ? length : -length),
							ys: line.ys,
							xe: line.xe - (line.xe - line.xs > 0 ? -length : length),
							ye: line.ye
						}
					}
				}
				let lineLength = this.lineLength(line)
				let k = length / lineLength;
				let x = line.xe - line.xs;
				let y = line.ye - line.ys;
				return {
					xs: line.xs - k * x,
					ys: line.ys - k * y,
					xe: line.xe + k * x,
					ye: line.ye + k * y
				}
			}
			lineLengthScale(line, scale) { // 线段长度缩放 返回缩放后的线段
				let length = this.lineLength(line)
				return this.lineLengthAdd(line, (length * scale - length) / 2)
			}
			vectorMove(line, len) { // 返回线段起点向终点移动len距离后的坐标
				let { xs, ys, xe, ye } = line
				if (xs == xe) {
					ys = ys + (ye > ys ? len : -len)
				} else if (ys == ye) {
					xs = xs + (xe > xs ? len : -len)
				} else {
					let allLen = this.p2p({ x: xs, y: ys }, { x: xe, y: ye })
					let k = len / allLen;
					xs = (xe - xs) * k + xs
					ys = (ye - ys) * k + ys
				}
				return { x: xs, y: ys }
			}
			rodataLine(line, angle) { // 线段 顺时针旋转角度 
				angle = -this.angleToPi(angle)
				var sin = Math.sin(angle);
				if (Math.abs(angle - Math.atan2(0, -1)) < 0.0000001) { sin = 0 };
				var cos = Math.cos(angle);
				if (Math.abs(angle - Math.atan2(1, 0)) < 0.0000001) { cos = 0 };
				var x = (line.xe - line.xs) * cos - (line.ye - line.ys) * sin + (line.xs - 0);
				var y = (line.xe - line.xs) * sin + (line.ye - line.ys) * cos + (line.ys - 0);
				return { xs: line.xs, ys: line.ys, xe: x, ye: y }
			}
			translateLine(line, len) { // 线段向右平移 平移距离 len
				var line_tmp = {}
				var lineLength = Math.sqrt((line.xe - line.xs) * (line.xe - line.xs) + (line.ye - line.ys) * (line.ye - line.ys))
				line_tmp.xe = line.xe - (len / lineLength) * (line.ys - line.ye)
				line_tmp.ye = line.ye - (len / lineLength) * (line.xe - line.xs)
				line_tmp.xs = line.xs - (len / lineLength) * (line.ys - line.ye)
				line_tmp.ys = line.ys - (len / lineLength) * (line.xe - line.xs)
				return line_tmp
			}

			// 碰撞检测类
			pointTouchLimits(p, limit) { // 点在范围内
				let { xmin, xmax, ymin, ymax } = limit
				if (p.x >= xmin && p.x <= xmax && p.y >= ymin && p.y <= ymax) {
					return true
				}
			}
			rectTouchRect(rect1, rect2) { // 矩形touch
				let rectsWidth = (rect1.width + rect2.width) / 2;
				let rectsHeight = (rect1.height + rect2.height) / 2;
				let xOffset = Math.abs(rect2.x - rect1.x);
				let yOffset = Math.abs(rect2.y - rect1.y);
				if (xOffset <= rectsWidth && yOffset <= rectsHeight) {
					return true
				}
			}
			rectTouchLimits(rect, limit) {  // 无角度矩形在 limit范围内 非精确
				let { x, y, width, height } = rect
				let xc = limit.xmin + (limit.xmax - limit.xmin) / 2
				let yc = limit.ymin + (limit.ymax - limit.ymin) / 2
				let xsize = Math.abs(limit.xmax - limit.xmin)
				let ysize = Math.abs(limit.ymax - limit.ymin)
				return this.rectTouchRect(rect, { x: xc, y: yc, width: xsize, height: ysize })
			}
		}

		let math = new ScottMath();
	
		class CVS {
			constructor(props) {
				this.canvas = document.querySelector('#' + props.id);
				this.ctx = this.canvas.getContext("2d");
				this.width = this.canvas.width;  // 画布宽度
				this.height = this.canvas.height; // 画布高度
				this.originX = this.canvas.width / 2; // 设置原点x坐标 原点相当于坐标轴 0, 0 
				this.originY = this.canvas.height / 2; // 设置原点y坐标
				this.windowLimits = { xmin: 0, ymin: 0, xmax: 0, ymax: 0 }; // 画布窗口范围
				this.symbols = props.symbols || [];
				this.hooks = {
					mouseXYChange() { },  // 鼠标位置坐标变动
					scaleChange() { },  // 缩放倍率变动
					renderOver() { }, // 绘制结束
					keydown() { }, // 键盘按下
				}
				this.renderCount = {
					rect: 0,
					pad: 0,
					font: 0,
					line: 0
				}
				// 摄像头 
				this.camera = { x: props.cx || 0, y: props.cy || 0, scaleX: 1.9, scaleY: 1.9, scaleMax: 10, scaleMin: 0.1 }

				this.init();
			}
			resetRenderCount () {
				this.renderCount = {
					rect: 0,
					pad: 0,
					font: 0,
					line: 0
				}
			}
			init() {
				// this.mousemove = throttle( this.mousemove, 10);
				// this.mousewheel = throttle( this.mousewheel, 200);

				this.canvas.addEventListener("mousemove", this.mousemove.bind(this));
				this.canvas.addEventListener("mousedown", this.mousedown.bind(this));
				this.canvas.addEventListener("mouseup", this.mouseup.bind(this));
				this.canvas.addEventListener("mouseover", this.mouseover.bind(this));
				this.canvas.addEventListener("mousewheel", this.mousewheel.bind(this));
				// this.canvas.addEventListener("click", this.click.bind(this))

				window.addEventListener("keydown", this.keydown.bind(this));
				window.addEventListener("keyup", this.keyup.bind(this));
			}
			cvsXY2originXY(x, y, reverse) { // 画布坐标和原点坐标相互转换
				if (reverse) {
					return { x: x + this.originX, y: this.originY - y }
				}
				return { x: x - this.originX, y: this.originY - y }
			}
			cameraScale(props) { // 摄像头缩放
				let { scale } = props;
				let scale_old = this.camera.scaleX;
				if (scale > this.camera.scaleMax) {
					scale = this.camera.scaleMax;
				} else if (scale < this.camera.scaleMin) {
					scale = this.camera.scaleMin;
				}
				scale = scale.toFixed(1) - 0;
				if (scale_old != scale) {
					this.camera.scaleX = scale;
					this.camera.scaleY = scale;
					this.hooks.scaleChange({ scale });
					this.render();
				}
			}
			// 事件
			mousemove(e) {
				let { offsetX, offsetY } = e
				let ox = (offsetX - this.width / 2) / this.camera.scaleX + this.camera.x;
				let oy = (this.height / 2 - offsetY) / this.camera.scaleY + this.camera.y;
				let moveX = (e.offsetX - this.mousedownX);
				let moveY = (e.offsetY - this.mousedownY);

                if(this.mousedownFlag){
                    this.camera.x -= moveX / this.camera.scaleX
                    this.camera.y += moveY / this.camera.scaleY
                    this.render()
                    this.mousedownX = e.offsetX
                    this.mousedownY = e.offsetY
                }else {
                    this.hooks.mouseXYChange({ox, oy})
                }
			}
			mousedown(e) {
                let { offsetX, offsetY } = e;
                let ox = (offsetX - this.width / 2) / this.camera.scaleX + this.camera.x;
                let oy = (this.height / 2 - offsetY) / this.camera.scaleY + this.camera.y;
                let moveX = (e.offsetX - this.mousedownX)/(this.camera.scaleX);
                let moveY = (e.offsetY - this.mousedownY)/(this.camera.scaleY);
                this.mousedownX = e.offsetX;
                this.mousedownY = e.offsetY;
                this.mousedownFlag = true;
			}
			mouseup(e) {
                this.mousedownFlag = false
			}
			mouseover(e) {
				this.mousedownFlag = false
			}
			mousewheel(e) {
				if (e.deltaY < 0) {
					this.cameraScale({ scale: this.camera.scaleX + 0.1 })
				} else {
					this.cameraScale({ scale: this.camera.scaleX - 0.1 })
				}
			}
			keyup(e) { // 键盘松开
				let code = e.code;
				switch (code) {
					
					default:
						break;
				}
			}
			keydown(e) { // 键盘按下事件
                let code = e.code;
                // console.log(e);
                switch (code) {
                    case "ArrowUp":
                        this.camera.y += 1
                        break;
                    case "ArrowLeft":
                        this.camera.x -= 1
                        break;
                    case "ArrowDown":
                        this.camera.y -= 1
                        break;
                    case "ArrowRight":
                        this.camera.x += 1
                        break;
                    default:
                        break;
                }
                if(/[WASD]/.test(code)) {
                    this.render()
                }
            }

			// 渲染
			render(tmpsymbols) { // 渲染画布
				this.resetRenderCount()
				if(tmpsymbols){
					this.tmpsymbols = tmpsymbols
				}
				
				let scaleOffsetX = this.width / this.camera.scaleX - this.width;
				let scaleOffsetY = this.height / this.camera.scaleY - this.height;

				// before
				this.ctx.save();
				this.ctx.translate(
					-this.camera.x * this.camera.scaleX - (this.width / 2 * (this.camera.scaleX - 1))
					, this.camera.y * this.camera.scaleY - (this.height / 2 * (this.camera.scaleY - 1))); // 视角锁定摄像头 
				this.ctx.scale(this.camera.scaleX, this.camera.scaleY); // 摄像头缩放
				this.ctx.clearRect(this.camera.x - scaleOffsetX / 2, -this.camera.y - scaleOffsetY / 2, this.width / this.camera.scaleX, this.height / this.camera.scaleY); // 清除画布
				// 计算屏幕内坐标
				this.windowLimits = {
					xmin: this.camera.x - this.width / 2 / this.camera.scaleX,
					ymin: this.camera.y - this.height / 2 / this.camera.scaleY,
					xmax: this.camera.x + this.width / 2 / this.camera.scaleX,
					ymax: this.camera.y + this.height / 2 / this.camera.scaleY,
				}
				if (this.background) {
					let { width, height } = this.background;
					width /= 2;
					height /= 2;
					this.ctx.drawImage(this.background, -width + (this.width/2), -height + (this.height/2), width * 2, height * 2);
				}

				// start
				this.renderSymbol(this.symbols); // 渲染symbols

                
				this.addPad({ scale: true, x: this.camera.x, y: this.camera.y, type: "pad", size: 4, attr: { color: "rgba(255,0,0,0.9)" } });  // 摄像头中心点
				this.drawOrigin({ size: 18 }); // 绘制原点
				if(this.tmpsymbols) {
					this.renderSymbol(this.tmpsymbols);
				}
				// end 
				this.ctx.restore();
				this.renderDoc();
			}
			renderDoc() {  // 渲染文档
				// cambra坐标
				this.hooks.renderOver()
			}

			// 屏幕内渲染 只绘制屏幕内的symbol 
			// draw
			
			renderSymbol(symbols) {
				let that = this;
				if(Array.isArray(symbols)) {
					symbols.forEach(symbol => { // 渲染symbols
						let type = symbol.type;
						if (type) {
							type = type[0].toUpperCase() + type.slice(1);
							if (that[`add${type}`]) {
								that[`add${type}`](symbol);
							}
						}
					});
				} else {
					let symbols_arr = Object.values(symbols);
					symbols_arr = symbols_arr.sort((a,b) => a.count - b.count)
					symbols_arr.forEach(symbol => { // 渲染symbols
						let type = symbol.type;
						if (type) {
							type = type[0].toUpperCase() + type.slice(1);
							if (that[`add${type}`]) {
								that[`add${type}`](symbol);
							}
						}
					});
				}
				
			}
			addFont(props) {
				let { str, textAlign, textBaseline, attr, size } = props;
				let { x, y } = this.cvsXY2originXY(props.x, props.y, true);
				let { xmin, ymin, xmax, ymax } = this.windowLimits;
				if(props.x <= xmax && props.x>= xmin && props.y<=ymax && props.y>=ymin){
					this.renderCount.font++
				} else {
					return "隐藏该文字"
				}
				this.ctx.save()
				this.ctx.beginPath()
				this.ctx.font = size + "px serif";
				this.ctx.textAlign = textAlign || "center"
				this.ctx.textBaseline = textBaseline || "middle"
				let textInfo = this.ctx.measureText(str);
				//  actualBoundingBoxAscent:  6.796875
				//  actualBoundingBoxDescent:  4.203125
				//  actualBoundingBoxLeft:  11
				//  actualBoundingBoxRight:  12
				//  fontBoundingBoxAscent:  9.796875
				//  fontBoundingBoxDescent:  7.203125
				//  width:  24
				let fix = textInfo.actualBoundingBoxDescent// + textInfo.actualBoundingBoxDescent;
				if (attr?.color) {
					this.ctx.fillStyle = attr.color
				}
				this.ctx.fillText(str, x, y + fix / 2);

				this.ctx.restore()
			}
			addPad(props) { // 添加圆形
				let { attr, size, scale } = props;
				let scaleRate = 1;
				if (scale) {
					scaleRate /= this.camera.scaleX;
				}
				// 是否在屏幕内需要渲染
				let { xmin, ymin, xmax, ymax } = this.windowLimits;
				if (props.x < xmin || props.x > xmax || props.y < ymin || props.y > ymax) {
					let p2p = Math.sqrt((this.camera.x - props.x) ** 2 + (this.camera.y - props.y));
					if (p2p > (Math.sqrt((this.width / 2) ** 2 + (this.height / 2) ** 2) + size / 2 * scaleRate)) {
						return '隐藏该symbol'
					}
				}
				if (props.hide) {
					return '隐藏该symbol'
				}
				this.renderCount.pad++
				let { x, y } = this.cvsXY2originXY(props.x, props.y, true);
				this.ctx.save();
				this.ctx.beginPath();
				if (attr?.color) {
					if (attr?.stroke) {
						this.ctx.strokeStyle = attr.color; // 颜色
					} else {
						this.ctx.fillStyle = attr.color; // 颜色
					}
				}


				if (attr?.lineDash) {
					if (scaleRate == 1) {
						this.ctx.setLineDash(attr.lineDash);
					} else {
						this.ctx.lineWidth *= scaleRate;
						this.ctx.setLineDash(attr.lineDash.map(v => v * scaleRate));
					}
				}

				this.ctx.arc(x, y, size / 2 * scaleRate, math.angleToPi(180), math.angleToPi(-180), false);
				if (attr?.stroke) {
					this.ctx.stroke();
				} else if (attr?.img) {
					let imgdata = attr.img;
					let { img } = imgdata;
					this.ctx.clip();
					let sizetmp = size * scaleRate;
					let sizetmpOffset = size * scaleRate / 2;
					let imgSize = img.width;
					let imgOffsetX = 0;
					let imgOffsetY = 0;
					if (img.width > img.height) {
						imgSize = img.height;
						imgOffsetX = (img.width - img.height) / 2;
					} else if (img.height > img.width) {
						imgOffsetY = (img.height - img.width) / 2
					}
					this.ctx.drawImage(img, imgOffsetX, imgOffsetY, imgSize, imgSize, x - sizetmpOffset, y - sizetmpOffset, sizetmp, sizetmp)
				} else {
					this.ctx.fill()
				}
				this.ctx.restore()
			}
			addLine(props) { // 添加线段
				let { xs, ys, xe, ye, size, scale, attr } = props;
				if (xs == undefined || ys == undefined || xe == undefined || ye == undefined) {
					return "缺少坐标"
				}
				let scaleRate = 1;
				if (scale) {
					scaleRate /= this.camera.scaleX;
					let lineChange = math.lineLengthScale({ xs, ys, xe, ye }, scaleRate);
					xs = lineChange.xs;
					ys = lineChange.ys;
					xe = lineChange.xe;
					ye = lineChange.ye;
				}
				// 是否在屏幕内需要渲染
				let { xmin, ymin, xmax, ymax } = this.windowLimits;
				// todo 线段是否在屏幕内
				if (!math.rectTouchRect({
					x: xs + (xe - xs) / 2,
					y: ys + (ye - ys) / 2,
					width: Math.abs(xe - xs) + size,
					height: Math.abs(ye - ys) + size,
				}, {
					x: this.camera.x,
					y: this.camera.y,
					width: this.width / this.camera.scaleX,
					height: this.height / this.camera.scaleY
				})) {
					return '隐藏该symbol'
				}
				if (props.hide) {
					return '隐藏该symbol'
				}

				let startSY = this.cvsXY2originXY(xs, ys, true);
				let endSY = this.cvsXY2originXY(xe, ye, true);
				xs = startSY.x;
				ys = startSY.y;
				xe = endSY.x;
				ye = endSY.y;

				this.ctx.save();
				this.ctx.beginPath();

				this.ctx.lineWidth = size;

				if (scaleRate != 1) {
					this.ctx.lineWidth = size * scaleRate;
				}
				if (attr?.lineDash) {
					if (scaleRate == 1) {
						this.ctx.setLineDash(attr.lineDash);
					} else {
						this.ctx.setLineDash(attr.lineDash.map(v => v * scaleRate));
					}
				}
				this.ctx.moveTo(xs, ys);
				this.ctx.lineTo(xe, ye);

				if (attr) {
					if (attr.color) {
						this.ctx.strokeStyle = attr.color; // 颜色
					}
				}
				this.ctx.stroke();
				this.ctx.restore();
				this.renderCount.line++
			}
			addRect(props) { //添加矩形
				let { attr, width, height, scale } = props;
				let scaleRate = 1;
				if (scale) {
					scaleRate /= this.camera.scaleX;
					width *= scaleRate;
					height *= scaleRate;
				}
				// 是否在屏幕内需要渲染 矩形因为没有角度 只需要判定4个顶点是不是都不在 winlimits里
				let { xmin, ymin, xmax, ymax } = this.windowLimits;
				if (!math.rectTouchRect(props, {
					x: this.camera.x,
					y: this.camera.y,
					width: this.width / this.camera.scaleX,
					height: this.height / this.camera.scaleY
				})) {
					return '隐藏该symbol'
				} 
				if (props.hide) {
					return '隐藏该symbol'
				}

				let { x, y } = this.cvsXY2originXY(props.x, props.y, true);
				this.ctx.save();
				this.ctx.beginPath();
					
				if (attr?.fill) {
					this.ctx.fillStyle = attr.color || attr.fill; // 颜色
				} else
				if (attr?.stroke) {
					this.ctx.strokeStyle = attr.color || attr.stroke; // 颜色
				} else if(attr?.img) {
                    let imgdata = attr.img;
                    let {img} = imgdata
                    this.ctx.clip();
                    let sizetmp = size * scaleRate
                    let sizetmpOffset = size * scaleRate / 2
                    let imgSize = img.width;
                    let imgOffsetX = 0;
                    let imgOffsetY = 0;
                    if(img.width > img.height) {
                        imgSize = img.height
                        imgOffsetX = (img.width - img.height ) / 2
                    } else if (img.height > img.width) {
                        imgOffsetY = (img.height - img.width ) / 2
                    }
                    this.ctx.drawImage(img, imgOffsetX, imgOffsetY, imgSize, imgSize, x-sizetmpOffset, y-sizetmpOffset, sizetmp, sizetmp)
				}
				
				if(attr?.lineWidth) {
					this.ctx.lineWidth = attr.lineWidth;
				}


				if (attr?.lineDash) {
					if (scaleRate == 1) {
						this.ctx.setLineDash(attr.lineDash);
					} else {
						this.ctx.lineWidth *= scaleRate;
						this.ctx.setLineDash(attr.lineDash.map(v => v * scaleRate));
					}
				}
				if (attr?.fill) {
					this.ctx.fillRect(x - width / 2, y - height / 2, width, height) // 填充矩形
				} else if (attr?.stroke){
					this.ctx.strokeRect(x - width / 2, y - height / 2, width, height) // 填充矩形
				} else {
					this.ctx.fillRect(x - width / 2, y - height / 2, width, height) // 填充矩形
				}
				this.ctx.restore()
				this.renderCount.rect++
			}
			drawOrigin(props) { // 绘制原点
				let size = props.size || 10;
				if (size < 4) { size = 4 }
				let offset = (size / 2 - 1);
				this.renderSymbol([
					{ x: 0, y: 0, type: "pad", scale: true, size: size, attr: { color: "rgba(0, 0, 0, 0.8)", stroke: true, lineDash: [2] } },
					{ xs: -offset, ys: 0, xe: offset, ye: 0, type: "line", scale: true, size: 1, attr: { color: "rgba(0, 0, 0, 0.8)", lineDash: [2] } },
					{ xs: 0, ys: offset, xe: 0, ye: -offset, type: "line", scale: true, size: 1, attr: { color: "rgba(0, 0, 0, 0.8)", lineDash: [2] } },
				])
			}
		}

		let cvs = new CVS({ id: "puppeteerScreenShortcvs", cx: -714, cy:544 });

		cvs.hooks.scaleChange = function (props) { // 缩放倍率改变
			document.querySelector("#scaleRate").value = props.scale;
		}
		cvs.hooks.mouseXYChange = function (props) { // 鼠标移动
			let { ox, oy } = props
			document.querySelector('#mouseXY').innerHTML = `x:${ox.toFixed(0)} y:${oy.toFixed(0)}`;
		}
		cvs.hooks.renderOver = function (props) { // 画布渲染结束
			document.querySelector("#cameraXY").innerHTML = `x:${cvs.camera.x.toFixed(0)} y:${cvs.camera.y.toFixed(0)}`  // 绘制摄像头坐标
			if (cvs.windowLimits) {
				winLimitEl.innerHTML = `xmin:${cvs.windowLimits.xmin.toFixed(0)} ymin:${cvs.windowLimits.ymin.toFixed(0)} xmax:${cvs.windowLimits.xmax.toFixed(0)} ymax:${cvs.windowLimits.ymax.toFixed(0)}`  // 绘制摄像头坐标
				renderSymbolEl.innerHTML = JSON.stringify(cvs.renderCount)  // 绘制摄像头坐标
			}
		}
		cvs.hooks.keydown = function (code) { // 
			if (/^Key([WASD])$/.test(code)) {
				let direction = RegExp.$1;
				if (direction == "W") {
					direction = "上"
				} else if (direction == "S") {
					direction = "下"
				} else if (direction == "A") {
					direction = "左"
				} else if (direction == "D") {
					direction = "右"
				}
				let com = "向" + direction + "移动";

			}
		}
		document.querySelector('#scaleRate').addEventListener("change", (e) => {
			let value = e.target.value - 0;
			if (/\d\.?\d*/.test(value)) {
				cvs.cameraScale({ scale: value })
			}
		});
		

		let renderCats = {
			"巨鹫之像": false,
			"密域": false,
			"地下城": false,
			"高塔": false,
			"翠叶鼠雕像": false,
			"宝箱": false,
			"矿石": false,
			"商人": false,
			"BOSS": true,
			"待整理": false,
			"篝火": false,
			"技能果树": false,
			"帕鲁蛋": false,
			"对峙": false,
			"帕鲁神像": false,
			"漂流者手记": false,
		}

		let selectBtns = document.querySelector("#selectBtns");
		let selectbtnhtml = ""
		Object.keys(renderCats).forEach(k => {
			selectbtnhtml += `
				<button id="${k}" class="btn">${k}</button>
			`
		});
		selectBtns.innerHTML = selectbtnhtml
		Object.keys(renderCats).forEach(k => {
			document.querySelector("#" + k).addEventListener("click", e => {
				renderCats[e.target.id] = !renderCats[e.target.id]
			});
		});

		function renderMap () {
			let rendersymbols = []

			for (let catkey in renderCats) {
				if(renderCats[catkey]) {
					cats[catkey].forEach(data => {
						rendersymbols.push({type:"pad", y:data.latitude*1000, x:data.longitude*1000, size: 20, attr:{color: "#09f", stroke: true, lineDash: [2]} })
						rendersymbols.push({type:"font", y:data.latitude*1000, x:data.longitude*1000, size: 10, str:data.title , attr:{color: "#888"} })
					})
				}
			}
			
			cvs.symbols = rendersymbols

			cvs.render()
		}


		document.querySelector("#btn0").addEventListener("click", e => {
			for(let key in renderCats){ renderCats[key] = false }
		});
		
		document.querySelector("#btn1").addEventListener("click", e => {
			renderMap()
		});
		
		
		renderMap()
















		
		btn_cvs_add.addEventListener('click', e => {
			document.querySelector("#puppeteerScreenShortcvs").width+=100;
			document.querySelector("#puppeteerScreenShortcvs").height+=100;
			cvs.width = cvs.canvas.width;  // 画布宽度
			cvs.height = cvs.canvas.height; // 画布高度
			cvs.originX = cvs.canvas.width / 2; // 设置原点x坐标 原点相当于坐标轴 0, 0 
			cvs.originY = cvs.canvas.height / 2; // 设置原点y坐标
			cvs.render()
		});
		btn_cvs_reduce.addEventListener('click', e => {
			if(document.querySelector("#puppeteerScreenShortcvs").width > 100) {
				document.querySelector("#puppeteerScreenShortcvs").width-=100;
				document.querySelector("#puppeteerScreenShortcvs").height-=100;
				cvs.width = cvs.canvas.width;  // 画布宽度
				cvs.height = cvs.canvas.height; // 画布高度
				cvs.originX = cvs.canvas.width / 2; // 设置原点x坐标 原点相当于坐标轴 0, 0 
				cvs.originY = cvs.canvas.height / 2; // 设置原点y坐标
				cvs.render()
			}
		});




		function throttle(fn, ms) { // 节流
			let flag = true
			return function () {
				if (!flag) return
				flag = false
				setTimeout(() => {
					fn.apply(this, arguments)
					flag = true
				}, ms)
			}
		}

	</script>

</body>

</html>